package com.wangwei.routercompiler;

import com.google.auto.service.AutoService;
import com.wangwei.annotationrouter.Factory;

import java.io.IOException;
import java.lang.annotation.Retention;
import java.sql.Types;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Filter;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.tools.Diagnostic;

@AutoService(Processor.class)
public class RouterProcessor extends AbstractProcessor {
    /**
     * package a;    // PackageElement
     * public class Foo{ // TypeElement
     * private int a;  // VariableElement
     * private Foo other;
     * public Foo(){} //ExecuteableElement
     * public void set(//ExecuteableElement
     * int a){ //VariableElement
     * <p>
     * }
     * <p>
     * <p>
     * }
     */
    private javax.lang.model.util.Types typeUtils;
    private Messager messager;
    private Filer filter;
    private Elements elementsUtils;
    // type() 完整的名字  每个工厂是一个成员
    private Map<String, FactoryGroupedClasses> factoryClssess = new LinkedHashMap<>();

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        typeUtils = processingEnvironment.getTypeUtils();
        elementsUtils = processingEnvironment.getElementUtils();
        filter = processingEnvironment.getFiler();
        messager = processingEnvironment.getMessager();

    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> annotations = new LinkedHashSet<>();
        annotations.add(Factory.class.getCanonicalName());//
        return annotations;

    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    @Override
    public Set<String> getSupportedOptions() {
        return super.getSupportedOptions();
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {

        for (Element annotatedElement : roundEnvironment.getElementsAnnotatedWith(Factory.class)) {

            if (annotatedElement.getKind() != ElementKind.CLASS) {
                //注解的不是一个类
                error(annotatedElement, "@%s注解只能应用在类上，", Factory.class.getSimpleName());
                return true;
            }
            TypeElement typeElement = (TypeElement) annotatedElement;
            try {
                FactoryAnotatedClass factoryAnotatedClass = new FactoryAnotatedClass(typeElement);
                //check
                if (!isValidClass(factoryAnotatedClass)) {
                    return true;
                }
                //
                FactoryGroupedClasses factoryGroupedClasses = factoryClssess.get(factoryAnotatedClass.getQualifedSuperClassName());
                if (factoryGroupedClasses == null) {
                    String qualifiedGroupName = factoryAnotatedClass.getQualifedSuperClassName();
                    factoryGroupedClasses = new FactoryGroupedClasses(qualifiedGroupName);
                    factoryClssess.put(qualifiedGroupName, factoryGroupedClasses);
                }
                factoryGroupedClasses.add(factoryAnotatedClass);


            } catch (IllegalArgumentException iag) {
                //id 为空
                error(typeElement, iag.getMessage());
                return true;
            } catch (IdAlreadyUsedException e) {
                // id已存在
                error(typeElement, e.getMessage());
                return true;
            }
        }
        try {
            for (FactoryGroupedClasses factoryClass : factoryClssess.values()) {
                factoryClass.generateCode(elementsUtils, filter);
            }
        }catch (IOException e){
            error( e.getMessage());
        }
        factoryClssess.clear();
        return true;
    }

    private boolean isValidClass(FactoryAnotatedClass item) {
        //
        TypeElement classElement = item.getAnnotatedClassElement();

        // 必须继承 type的class
        // 必须提供一个没有单数的构造器
        // id 必须为String  且唯一
        if (!classElement.getModifiers().contains(Modifier.PUBLIC)) {
            // 必须是public
            error(classElement, "class %s Not public", classElement.getQualifiedName().toString());
            return false;
        }
        if (classElement.getModifiers().contains(Modifier.ABSTRACT)) {
            // 必须是public
            error(classElement, "class %s Not abstract", classElement.getQualifiedName().toString());
            return false;
        }
        //Meal.class
        TypeElement superClassElement = elementsUtils.getTypeElement(item.getQualifedSuperClassName());
        if (superClassElement.getKind() == ElementKind.INTERFACE) {
            // 是一个接口
            if (!classElement.getInterfaces().contains(superClassElement.asType())) {
                error(classElement, "The class %s annotated with @%s must implement the interface %s",
                        classElement.getQualifiedName().toString(), Factory.class.getSimpleName(),
                        item.getQualifedSuperClassName());
                return false;
            }


        } else {
            //是一个类
            TypeElement currentClass = classElement;

            for (; ; ) {
                TypeMirror superClassType = currentClass.getSuperclass();
                if (superClassType.getKind() == TypeKind.NONE) {
                    // 到达了基本类型(java.lang.Object), 所以退出
                    error(classElement, "The class %s annotated with @%s must inherit from %s",
                            classElement.getQualifiedName().toString(), Factory.class.getSimpleName(),
                            item.getQualifedSuperClassName());
                    return false;
                }
                if (superClassType.toString().equals(item.getQualifedSuperClassName())) {
                    // 找到了要求的父类
                    break;
                }

                currentClass = (TypeElement) typeUtils.asElement(superClassType);
            }

        }
        return true;


    }

    private void error(Element e, String msg, Object... args) {
        messager.printMessage(Diagnostic.Kind.ERROR, String.format(msg, args), e);
    }
    private void error( String msg) {
        messager.printMessage(Diagnostic.Kind.ERROR, msg);
    }
}
